import { DependencyContainer, container } from "tsyringe";
import {
    Body, ENV, Headers, IRequest, IResponse, NextFunction,
    Query, ROOT, Request, Response, INextFunction, ForbiddenError,
    Router, ClearCache, WEBSOCKET, WEBSOCKETS, currentUsers, createToken, verifyToken, useEntityManager
} from "@sker/core";
import { LoggerOptions, SimpleConsoleLogger } from "typeorm";
import type { SysUser } from '@sker/entities'
import { join } from "path";
import { readFileSync } from "fs";
import { WxMember, WxToken } from '@sker/entities';

declare const injector: DependencyContainer;

export const useToken = (): any => {
    const headers = injector.resolve(Headers)
    const authorization = headers.authorization;
    return verifyToken(authorization)
}

export const useConfig = (name?: string) => {
    if (!name) {
        const router = new Router(injector)
        const { scope, addon } = router;
        name = `@${scope}/${addon}.json`
    }
    const root = injector.resolve(ROOT)
    const jsonFile = join(root, 'data', 'addons', name)
    try {
        return JSON.parse(readFileSync(jsonFile, 'utf-8'))
    } catch (e) {
        return {}
    }
}

export const useReqIp = () => {
    const req = useRequest()
    return (req.headers['x-forwarded-for'] || req.socket.remoteAddress || req.ip) as string
}

export function useSession<T = any>(): T {
    const req = useRequest()
    return Reflect.get(req, 'session') as T;
}
/**
 * 
 * @param thowForbidden 为true时，检查权限，并抛出403异常
 * @returns 
 */
export function useCurrentUser(thowForbidden: boolean = false) {
    const session = useSession();
    const currentUser = session.currentUser;
    if (thowForbidden && !currentUser) {
        throw new ForbiddenError(`登录失效，请重新登录!`)
    }
    return [
        session.currentUser,
        (user: SysUser) => {
            session.currentUser = user
        },
        () => {
            session.currentUser = null
            currentUsers.delete(currentUser.id)
        }
    ]
}

export async function useAuthorization(){
    const headers = useReqHeaders();
    const authorization: string = headers.authorization
    if (!authorization) return;
    const [bearer, token] = authorization.split(' ');
    return token;
}
export async function useCurrentMember() {
    const headers = useReqHeaders();
    const authorization: string = headers.authorization
    if (!authorization) throw new ForbiddenError(`登录失效，请重新登录`)
    const [bearer, token] = authorization.split(' ');
    if (!token) throw new ForbiddenError(`登录失效，请重新登录`)
    const wxToken = await useEntityManager(async (m) => {
        const wxToken = await m.findOne(WxToken, { where: { token: token, status: '1' } })
        if (!wxToken) throw new ForbiddenError(`登录失效，请重新登录`)
        return wxToken;
    })
    if (!wxToken) {
        throw new ForbiddenError(`登录失效，请重新登录`)
    }
    return [
        wxToken.session,
        async (user: any) => {
            wxToken.session = user
            await useEntityManager(async m => {
                await m.update(WxToken, wxToken.id, { session: user })
            })
        },
        async () => {
            wxToken.session = null
            await useEntityManager(async m => {
                await m.update(WxToken, wxToken.id, { session: null })
            })
        }
    ]
}
export function useCurrentAccount() {
    return useSession().currentAccount;
}
export function useCurrentCompany(thowForbidden: boolean = false) {
    const session = useSession();
    const currentCompany = session.currentCompany;
    if (thowForbidden && !currentCompany) {
        throw new ForbiddenError(`登录失效，请重新登录`)
    }
    return [
        session.currentCompany,
        (user: any) => {
            session.currentCompany = user
        },
        () => {
            session.currentUser = null
        }
    ]
}

export function useData() {
    const body = injector?.resolve(Body)
    const query = injector?.resolve(Query)
    return {
        ...query,
        ...body
    }
}

export function useReqBody() {
    return injector?.resolve(Body)
}

export function useReqQuery() {
    return injector?.resolve(Query)
}

export function useReqHeaders() {
    return injector?.resolve(Headers)
}

export function useEnv() {
    return injector?.resolve(ENV)
}

export function useRoot() {
    return injector?.resolve(ROOT)
}

export function useRequest(): IRequest {
    return injector?.resolve(Request)
}

export function useResponse(): IResponse {
    return injector?.resolve(Response)
}

export function useNextFunction(): INextFunction {
    return injector?.resolve(NextFunction)
}

export class Logger extends SimpleConsoleLogger {
    constructor(public name: string, level: LoggerOptions) {
        super(level);
    }
}
let logger: Logger | undefined;

export function useLogger(name: string) {
    const req = useRequest()
    const level: LoggerOptions = req.headers.ll || req.query.ll || req.body.ll;
    if (logger) return logger;
    logger = new Logger(name, level)
    return logger;
}
export async function useClearCache() {
    const clearCaches = injector.resolveAll(ClearCache)
    console.log(`clear cache ${clearCaches.length}`)
    await Promise.all(clearCaches.map(c => c()))
}
/**
 * 单发
 * @param msg 
 */
export function useSend(msg: string | Buffer) {
    const ws = injector.resolve(WEBSOCKET)
    ws.send(msg)
}
export function useCloseWs() {
    const ws = injector.resolve(WEBSOCKET)
    ws.close()
}
/**
 * 链接群发
 */
export function useSends(msg: string | Buffer) {
    const wss = container.resolve(WEBSOCKETS)
    console.log(`sockets length ${wss?.size || 0}`)
    wss?.forEach(ws => ws.send(msg))
}

export function useSendAll(msg: string | Buffer) {
    const wss = container.resolve(WEBSOCKETS)
    wss.forEach(ws => {
        ws.send(msg)
    })
}

export function sendTo(uid: string, msg: string | Buffer) {
    const wss = container.resolve(WEBSOCKETS)
    const cacheKey = currentUsers.get(uid)
    const sockets = wss.get(cacheKey)
    sockets.send(msg)
}